package javaproject;

import java.util.Random;
import javax.media.j3d.LineArray;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.vecmath.Color3f;
import javax.vecmath.Vector3d;
import javax.media.j3d.Appearance;
import javax.vecmath.Color4f;

class BlockWall extends BasicBlock{
    static final int NORMAL_X = 0;
    static final int NORMAL_Y = 1;
    static final int NORMAL_Z = 2;
    public int normal;
    public int hole[][];
    public boolean valid;
    private Shape3D[][][] shape;
    private int axis1, axis2;
    private int[] margin;
    private float offset1, offset2;
    private float[][] cubeVertices;
    
    private float[] RGB = new float[3];
    private QuadArray[][][] cube;

    BlockWall(float[] dim, int[] margin, int multiplier, int normal, Appearance app, float alpha, float offset, int[][] hole)
    {
        super(dim,new double[]{0,0,0},app,alpha,offset);

        this.margin = margin;
        this.normal = normal;
        this.hole = hole;

	valid = false;

        switch(normal)
        {
            case NORMAL_X:
                axis1 = 1;
                axis2 = 2;
                for(int i = 0; i < 8; i++)
                {
                    verts[i][1] *= multiplier;
                    verts[i][2] *= multiplier;
                }
                break;
            case NORMAL_Y:
                axis1 = 0;
                axis2 = 2;
                for(int i = 0; i < 8; i++)
                {
                    verts[i][0] *= multiplier;
                    verts[i][2] *= multiplier;
                }
                break;
            case NORMAL_Z:
                axis1 = 0;
                axis2 = 1;
                for(int i = 0; i < 8; i++)
                {
                    verts[i][0] *= multiplier;
                    verts[i][1] *= multiplier;
                }
                break;
        }

        cubeVertices = new float[][]
        {
            //上
            {verts[4][0]+offset,verts[4][1]+offset,verts[4][2]-offset,    verts[5][0]-offset,verts[5][1]+offset,verts[5][2]-offset,    verts[7][0]-offset,verts[7][1]-offset,verts[7][2]-offset,    verts[6][0]+offset,verts[6][1]-offset,verts[6][2]-offset},
            //下
            {verts[0][0]+offset,verts[0][1]+offset,verts[0][2]+offset,    verts[2][0]+offset,verts[2][1]-offset,verts[2][2]+offset,    verts[3][0]-offset,verts[3][1]-offset,verts[3][2]+offset,    verts[1][0]-offset,verts[1][1]+offset,verts[1][2]+offset},
            //左
            {verts[0][0]+offset,verts[0][1]+offset,verts[0][2]+offset,    verts[4][0]+offset,verts[4][1]+offset,verts[4][2]-offset,    verts[6][0]+offset,verts[6][1]-offset,verts[6][2]-offset,    verts[2][0]+offset,verts[2][1]-offset,verts[2][2]+offset},
            //右
            {verts[1][0]-offset,verts[1][1]+offset,verts[1][2]+offset,    verts[3][0]-offset,verts[3][1]-offset,verts[3][2]+offset,    verts[7][0]-offset,verts[7][1]-offset,verts[7][2]-offset,    verts[5][0]-offset,verts[5][1]+offset,verts[5][2]-offset},
            //前
            {verts[0][0]+offset,verts[0][1]+offset,verts[0][2]+offset,    verts[1][0]-offset,verts[1][1]+offset,verts[1][2]+offset,    verts[5][0]-offset,verts[5][1]+offset,verts[5][2]-offset,    verts[4][0]+offset,verts[4][1]+offset,verts[4][2]-offset},
            //後
            {verts[3][0]-offset,verts[3][1]-offset,verts[3][2]-offset,    verts[2][0]+offset,verts[2][1]-offset,verts[2][2]+offset,    verts[6][0]+offset,verts[6][1]-offset,verts[6][2]-offset,    verts[7][0]-offset,verts[7][1]-offset,verts[7][2]-offset},
        };

        offset1 = dim[axis1]*2*multiplier;              //每個方塊之間的距離
        offset2 = dim[axis2]*2*multiplier;              //每個方塊之間的距離

        shape = new Shape3D[margin[axis1]*2+1][margin[axis2]*2+1][6];

	Color3f intrinsicColor = new Color3f();
	app.getColoringAttributes().getColor(intrinsicColor);

	RGB[0] = intrinsicColor.x;
	RGB[1] = intrinsicColor.y;
	RGB[2] = intrinsicColor.z;

	cube = new QuadArray[margin[axis1]*2+1][margin[axis2]*2+1][6];

	for(int l = -margin[axis1], i = 0; l <= margin[axis1]; l++, i++)
            for(int m = -margin[axis2], j = 0; m <= margin[axis2]; m++, j++)
            {

                for(int a = 0; a < 6; a++)
                {

                    cube[i][j][a] = new QuadArray(4, QuadArray.COORDINATES | QuadArray.COLOR_4);
                    float[] boxColor = new float[16];

                    for(int b = 0; b < 4; b++)
                    {
                        cubeVertices[a][b*3+axis1]+=offset1*l;
                        cubeVertices[a][b*3+axis2]+=offset2*m;
                        boxColor[b*4] = RGB[0];
                        boxColor[b*4+1] = RGB[1];
                        boxColor[b*4+2] = RGB[2];
                        boxColor[b*4+3] = alpha;
                    }
                    cube[i][j][a].setCapability(LineArray.ALLOW_COLOR_WRITE);
                    cube[i][j][a].setCoordinates(0, cubeVertices[a]);
                    cube[i][j][a].setColors(0, boxColor);
                    shape[i][j][a] = new Shape3D(cube[i][j][a], app);
                    //transG.insertChild(shape[i][j][a],a);
                    transG.addChild(shape[i][j][a]);

                    //為了重複利用變數，把lineVertices改回預設
                    for(int b = 0; b < 4; b++)
                    {
                        cubeVertices[a][b*3+axis1]-=offset1*l;
                        cubeVertices[a][b*3+axis2]-=offset2*m;
                    }
                }
            }
        hideHole();
    }
    private void hideHole()
    {
	Color4f show = new Color4f(RGB[0], RGB[1], RGB[2], alpha);
	Color4f[] shows = new Color4f[]{show, show, show, show};
	Color4f hide = new Color4f(RGB[0], RGB[1], RGB[2], 0);
	Color4f[] hides = new Color4f[]{hide, hide, hide, hide};
        for(int l = -margin[axis1], i = 0; l <= margin[axis1]; l++, i++)
            for(int m = -margin[axis2], j = 0; m <= margin[axis2]; m++, j++)
            {
                boolean[] needToDraw = needToDraw(l,m);

                for(int a = 0; a < 6; a++)
                {
		    if(needToDraw[a])
			cube[i][j][a].setColors(0, shows);
		    else
			cube[i][j][a].setColors(0, hides);
                }
            }
    }
    private boolean[] needToDraw(int l, int m)
    {
        boolean[] temp;
	    temp = new boolean[]{true,true,true,true,true,true};
        if(hole[0][axis1] <= l && l <= hole[1][axis1] && hole[0][axis2] <= m && m <= hole[1][axis2])    //判斷要畫的位置是不是在洞裡，是的話把alpha設為0
            temp = new boolean[]{false,false,false,false,false,false};
        return temp;
    }
    public int[][] generateHole()
    {
        //產生隨機空洞
        Random random = new Random();
        int temp1, temp2, x1, x2, y1, y2, z1, z2;
        temp1 = (random.nextInt(Config.edgeLength+1))-Config.edgeLength/2;
        temp2 = (random.nextInt(Config.edgeLength+1))-Config.edgeLength/2;
        x1 = Math.min(temp1, temp2);
        x2 = Math.max(temp1, temp2);
        temp1 = (random.nextInt(Config.edgeLength+1))-Config.edgeLength/2;
        temp2 = (random.nextInt(Config.edgeLength+1))-Config.edgeLength/2;
        y1 = Math.min(temp1, temp2);
        y2 = Math.max(temp1, temp2);
        temp1 = (random.nextInt(Config.edgeLength+1))-Config.edgeLength/2;
        temp2 = (random.nextInt(Config.edgeLength+1))-Config.edgeLength/2;
        z1 = Math.min(temp1, temp2);
        z2 = Math.max(temp1, temp2);
        return new int[][]{{x1, y1, z1}, {x2, y2, z2}};
    }
    public void setHole(int[][] hole)
    {
        this.hole = hole;
        hideHole();
    }
    public boolean isEnd()  //牆壁移動到邊緣了?
    {
	switch(normal)    
	{
	    case NORMAL_X:
		if(x < -Config.blockW*Config.w)
		    return true;
		break;
	    case NORMAL_Y:
		if(y < -Config.blockH*Config.h)
		    return true;
		break;
	    case NORMAL_Z:
		if(z > Config.blockH*Config.d)
		    return true;
		break;
	}
	return false;
    }
    public void proceed(double wallSpeed)
    {
	if(isEnd())	//到邊緣了
	{
	    switch(normal)
	    {
		case NORMAL_X:
		    moveTo(Config.blockW*Config.w, 0, 0);
		    break;
		case BlockWall.NORMAL_Y:
		    moveTo(0, Config.blockH*Config.h, 0);
		    break;
		case BlockWall.NORMAL_Z:
		    moveTo(0, 0, Config.blockD*Config.d);
	    }
	}
	else
	{
	    switch(normal)
	    {
		case NORMAL_X:
		    move(-wallSpeed, 0, 0);
		    break;
		case NORMAL_Y:
		    move(0, -wallSpeed, 0);
		    break;
		case NORMAL_Z:
		    move(0, 0, -wallSpeed);
		    break;
	    }
	}
    }
}
class BlockFrameWall extends BasicBlock{
    static final int NORMAL_X = 0;
    static final int NORMAL_Y = 1;
    static final int NORMAL_Z = 2;
    public boolean valid;
    private Shape3D[][][] shape;
    private int normal;
    private int[][] hole;
    private int[] margin;
    private int axis1, axis2;
    private float offset1, offset2;
    private float[][] lineVertices;

    private LineArray[][][] lines;
    private float[] RGB;

    BlockFrameWall(float[] dim, int[] margin, int multiplier, int normal, Appearance app, float alpha, int[][] hole)      //maxDim = {w,h,d}
    {
        super(dim,new double[]{0,0,0},app,alpha,0);

        this.margin = margin;
        this.normal = normal;
        this.hole = hole;

	valid = false;

        switch(normal)
        {
            case NORMAL_X:
                axis1 = NORMAL_Y;
                axis2 = NORMAL_Z;
                for(int i = 0; i < 8; i++)
                {
                    verts[i][1] *= multiplier;
                    verts[i][2] *= multiplier;
                }
                break;
            case NORMAL_Y:
                axis1 = NORMAL_X;
                axis2 = NORMAL_Z;
                for(int i = 0; i < 8; i++)
                {
                    verts[i][0] *= multiplier;
                    verts[i][2] *= multiplier;
                }
                break;
            case NORMAL_Z:
                axis1 = NORMAL_X;
                axis2 = NORMAL_Y;
                for(int i = 0; i < 8; i++)
                {
                    verts[i][0] *= multiplier;
                    verts[i][1] *= multiplier;
                }
                break;
        }

        //設定邊線座標
        lineVertices = new float[][]
        {
            {verts[0][0],verts[0][1],verts[0][2],     verts[1][0],verts[1][1],verts[1][2]},            //前下
            {verts[0][0],verts[0][1],verts[0][2],     verts[2][0],verts[2][1],verts[2][2]},            //左下
            {verts[2][0],verts[2][1],verts[2][2],     verts[3][0],verts[3][1],verts[3][2]},            //後下
            {verts[1][0],verts[1][1],verts[1][2],     verts[3][0],verts[3][1],verts[3][2]},            //右下
            {verts[0][0],verts[0][1],verts[0][2],     verts[4][0],verts[4][1],verts[4][2]},            //前左
            {verts[2][0],verts[2][1],verts[2][2],     verts[6][0],verts[6][1],verts[6][2]},            //左後
            {verts[1][0],verts[1][1],verts[1][2],     verts[5][0],verts[5][1],verts[5][2]},            //前右
            {verts[3][0],verts[3][1],verts[3][2],     verts[7][0],verts[7][1],verts[7][2]},            //右後
            {verts[4][0],verts[4][1],verts[4][2],     verts[6][0],verts[6][1],verts[6][2]},            //上左
            {verts[4][0],verts[4][1],verts[4][2],     verts[5][0],verts[5][1],verts[5][2]},            //前上
            {verts[6][0],verts[6][1],verts[6][2],     verts[7][0],verts[7][1],verts[7][2]},            //後上
            {verts[5][0],verts[5][1],verts[5][2],     verts[7][0],verts[7][1],verts[7][2]}            //上右
        };

        offset1 = dim[axis1]*2*multiplier;              //每個方塊之間的距離
        offset2 = dim[axis2]*2*multiplier;              //每個方塊之間的距離

        shape = new Shape3D[margin[axis1]*2+1][margin[axis2]*2+1][12];

	Color3f intrinsicColor = new Color3f();
	app.getColoringAttributes().getColor(intrinsicColor);
	RGB = new float[3];
	RGB[0] = intrinsicColor.x;
	RGB[1] = intrinsicColor.y;
	RGB[2] = intrinsicColor.z;
	
	lines = new LineArray[margin[axis1]*2+1][margin[axis2]*2+1][12];

        for(int l = -margin[axis1], i = 0; l <= margin[axis1]; l++, i++)
            for(int m = -margin[axis2], j = 0; m <= margin[axis2]; m++, j++)
            {
                for(int a = 0; a < 12; a++)
                {
                    lines[i][j][a] = new LineArray(2, LineArray.COORDINATES | LineArray.COLOR_4);

                    float[] lineColor = new float[8];

                    for(int b = 0; b < 2; b++)
                    {
                        lineVertices[a][b*3+axis1]+=offset1*l;
                        lineVertices[a][b*3+axis2]+=offset2*m;
                        lineColor[b*4] = RGB[0];
                        lineColor[b*4+1] = RGB[1];
                        lineColor[b*4+2] = RGB[2];
                        lineColor[b*4+3] = alpha;
                    }
                    lines[i][j][a].setCapability(LineArray.ALLOW_COLOR_WRITE);
                    lines[i][j][a].setCoordinates(0, lineVertices[a]);
                    lines[i][j][a].setColors(0, lineColor);
                    shape[i][j][a] = new Shape3D(lines[i][j][a], app);
                    transG.addChild(shape[i][j][a]);

                    //為了重複利用變數，把lineVertices改回預設
                    for(int b = 0; b < 2; b++)
                    {
                        lineVertices[a][b*3+axis1]-=offset1*l;
                        lineVertices[a][b*3+axis2]-=offset2*m;
                    }
                }
            }
        hideHole();
    }
    private void hideHole()
    {
	Color4f show = new Color4f(RGB[0], RGB[1], RGB[2], alpha);
	Color4f[] shows = new Color4f[]{show, show};
	Color4f hide = new Color4f(RGB[0], RGB[1], RGB[2], 0);
	Color4f[] hides = new Color4f[]{hide, hide};
        for(int l = -margin[axis1], i = 0; l <= margin[axis1]; l++, i++)
            for(int m = -margin[axis2], j = 0; m <= margin[axis2]; m++, j++)
            {
                boolean[] needToDraw = needToDraw(l,m);

                for(int a = 0; a < 12; a++)
                {
		    if(needToDraw[a])
			lines[i][j][a].setColors(0, shows);
		    else
			lines[i][j][a].setColors(0, hides);
                }
            }
    }
    private boolean[] needToDraw(int l, int m)
    {
        boolean[] temp;
        temp = new boolean[]{true,true,true,true,true,true,true,true,true,true,true,true};
        if(hole[0][axis1] <= l && l <= hole[1][axis1] && hole[0][axis2] <= m && m <= hole[1][axis2])    //判斷要畫的位置是不是在洞裡，是的話把alpha設為0
            temp = new boolean[]{false,false,false,false,false,false,false,false,false,false,false,false};
        return temp;
    }
    public void setHole(int[][] hole)
    {
        this.hole = hole;
        hideHole();
    }
    public boolean isEnd()  //牆壁移動到邊緣了?
    {
	switch(normal)
	{
	    case NORMAL_X:
		if(x < -Config.blockW*Config.w)
		    return true;
		break;
	    case NORMAL_Y:
		if(y < -Config.blockH*Config.h)
		    return true;
		break;
	    case NORMAL_Z:
		if(z < -Config.blockH*Config.d)
		    return true;
		break;
	}
	return false;
    }

    public void proceed(double wallSpeed)
    {
	if(isEnd())	//到邊緣了
	{
	    switch(normal)
	    {
		case NORMAL_X:
		    moveTo(Config.blockW*Config.w, 0, 0);
		    break;
		case NORMAL_Y:
		    moveTo(0, Config.blockH*Config.h, 0);
		    break;
		case NORMAL_Z:
		    moveTo(0, 0, Config.blockD*Config.d);
		    break;
	    }
	}
	else
	{
	    switch(normal)
	    {
		case NORMAL_X:
		    move(-wallSpeed, 0, 0);
		    break;
		case NORMAL_Y:
		    move(0, -wallSpeed, 0);
		    break;
		case NORMAL_Z:
		    move(0, 0, -wallSpeed);
		    break;
	    }
	}
    }
}